/**
 * 文件名: tauri/src/main.rs
 * 
 * 文件概述:
 * Tauri Rust后端，处理桌面版文件操作和系统集成，提供命令API供JavaScript调用。
 * 增强AI调用命令，支持多文件参考上下文。
 * 
 * 导入:
 * - tauri: Tauri框架核心
 * - serde: 序列化/反序列化支持(derive, Serialize, Deserialize)
 * - std::fs: 文件系统操作
 * - std::path: 路径操作
 * - reqwest: HTTP客户端(用于AI API调用)
 * 
 * 类型定义:
 * - #[derive(Serialize, Deserialize)]
 *   struct Chapter {
 *     id: String,
 *     title: String,
 *     content: String,
 *   }
 * 
 * - #[derive(Serialize, Deserialize)]
 *   struct ApiResponse<T> {
 *     data: Option<T>,
 *     error: Option<String>,
 *   }
 * 
 * - #[derive(Serialize, Deserialize)]
 *   struct AiRequest {
 *     prompt: String,
 *     context: Option<String>,  // 合并的上下文内容
 *   }
 * 
 * 工具函数:
 * - fn get_chapters_dir() -> std::path::PathBuf
 *   获取章节文件存储目录(用户文档或应用数据目录)
 * 
 * - fn estimate_tokens(text: &str) -> usize
 *   估算文本的token数量(简单实现，用于限制请求大小)
 * 
 * 命令函数:
 * - #[tauri::command]
 *   fn list_chapters() -> ApiResponse<Vec<Chapter>>
 *   列出章节文件，读取目录下所有JSON文件
 * 
 * - #[tauri::command]
 *   fn read_chapter(id: String) -> ApiResponse<Chapter>
 *   读取特定章节内容
 * 
 * - #[tauri::command]
 *   fn save_chapter(chapter: Chapter) -> ApiResponse<()>
 *   保存章节内容到文件
 * 
 * - #[tauri::command]
 *   async fn call_ai(request: AiRequest) -> ApiResponse<String>
 *   增强的AI调用函数，处理多文件参考上下文
 *   {
 *     // 获取环境变量中的API密钥
 *     // 估算token数量，超限则返回错误
 *     // 构建优化的OpenAI请求，包含系统提示和用户提示
 *     // 发送请求并处理响应
 *     // 处理各类错误情况
 *   }
 * 
 * 主函数:
 * - fn main()
 *   初始化Tauri应用，注册命令函数
 *   确保章节目录存在
 *   启动应用
 * 
 * AI API调用实现增强:
 * - 处理长文本上下文，考虑token限制
 * - 优化系统提示，增强AI使用参考文件的能力
 * - 请求添加超时控制，避免长时间等待
 * - 使用reqwest::Client提供更好的HTTP控制
 * 
 * 错误处理:
 * - 使用Result和ApiResponse结构统一处理错误
 * - 文件操作错误转换为用户友好消息
 * - API调用错误处理和超时控制
 * - 特殊处理token超限错误
 * 
 * 注意事项:
 * - 确保所有命令函数标记为#[tauri::command]
 * - 处理跨平台文件路径
 * - 异步函数(如API调用)需标记为async
 * - 安全处理用户数据和API密钥
 * - 考虑文件锁定和并发访问问题
 * - 增强的AI调用需处理大文本传输和响应
 */

// 导入必要库
use serde::{Serialize, Deserialize};
use std::fs;
use std::path::{Path, PathBuf};
use std::time::Duration;
use tauri::{AppHandle, Manager};
use tauri::api::path::document_dir;
use std::env;

// 章节数据结构
#[derive(Serialize, Deserialize, Clone)]
struct Chapter {
    id: String,
    title: String,
    content: String,
}

// API响应结构
#[derive(Serialize, Deserialize)]
struct ApiResponse<T> {
    data: Option<T>,
    error: Option<String>,
}

// AI请求结构
#[derive(Serialize, Deserialize)]
struct AiRequest {
    prompt: String,
    context: Option<String>,
}

// OpenAI API请求结构
#[derive(Serialize)]
struct OpenAiRequest {
    model: String,
    messages: Vec<Message>,
    temperature: f32,
}

// OpenAI API消息结构
#[derive(Serialize)]
struct Message {
    role: String,
    content: String,
}

// OpenAI API响应结构
#[derive(Deserialize)]
struct OpenAiResponse {
    choices: Vec<Choice>,
}

// OpenAI API选择结构
#[derive(Deserialize)]
struct Choice {
    message: ChatMessage,
}

// OpenAI API聊天消息结构
#[derive(Deserialize)]
struct ChatMessage {
    content: String,
}

// 获取章节文件存储目录
fn get_chapters_dir() -> PathBuf {
    let base_dir = if let Some(doc_dir) = document_dir() {
        doc_dir
    } else {
        std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
    };
    
    // 创建并返回章节目录路径
    base_dir.join("novelist").join("chapters")
}

// 估算文本的token数量(简单实现)
fn estimate_tokens(text: &str) -> usize {
    if text.is_empty() {
        return 0;
    }
    // 简单估算: 每4个字符约1个token
    (text.len() + 3) / 4
}

// 创建成功响应
fn success<T>(data: T) -> ApiResponse<T> {
    ApiResponse {
        data: Some(data),
        error: None,
    }
}

// 创建错误响应
fn error<T>(message: &str) -> ApiResponse<T> {
    ApiResponse {
        data: None,
        error: Some(message.to_string()),
    }
}

// 确保章节目录存在
fn ensure_chapters_dir_exists() -> Result<PathBuf, String> {
    let dir = get_chapters_dir();
    if !dir.exists() {
        fs::create_dir_all(&dir).map_err(|e| format!("无法创建章节目录: {}", e))?;
    }
    Ok(dir)
}

// 列出章节文件命令
#[tauri::command]
fn list_chapters() -> ApiResponse<Vec<Chapter>> {
    // 获取章节目录
    let chapters_dir = match ensure_chapters_dir_exists() {
        Ok(dir) => dir,
        Err(err) => return error(&err),
    };
    
    // 读取目录中的JSON文件
    let mut chapters = Vec::new();
    match fs::read_dir(chapters_dir) {
        Ok(entries) => {
            for entry in entries {
                if let Ok(entry) = entry {
                    let path = entry.path();
                    if path.is_file() && path.extension().map_or(false, |ext| ext == "json") {
                        // 读取章节文件
                        if let Ok(content) = fs::read_to_string(&path) {
                            if let Ok(chapter) = serde_json::from_str::<Chapter>(&content) {
                                chapters.push(chapter);
                            }
                        }
                    }
                }
            }
            success(chapters)
        }
        Err(e) => error(&format!("无法读取章节目录: {}", e)),
    }
}

// 读取特定章节内容命令
#[tauri::command]
fn read_chapter(id: String) -> ApiResponse<Chapter> {
    // 获取章节目录
    let chapters_dir = match ensure_chapters_dir_exists() {
        Ok(dir) => dir,
        Err(err) => return error(&err),
    };
    
    // 构建章节文件路径
    let file_path = chapters_dir.join(format!("{}.json", id));
    
    // 读取章节文件
    match fs::read_to_string(file_path) {
        Ok(content) => match serde_json::from_str::<Chapter>(&content) {
            Ok(chapter) => success(chapter),
            Err(e) => error(&format!("无法解析章节JSON: {}", e)),
        },
        Err(e) => error(&format!("无法读取章节文件: {}", e)),
    }
}

// 保存章节内容命令
#[tauri::command]
fn save_chapter(chapter: Chapter) -> ApiResponse<()> {
    // 验证章节数据
    if chapter.id.is_empty() || chapter.title.is_empty() {
        return error("章节ID和标题不能为空");
    }
    
    // 获取章节目录
    let chapters_dir = match ensure_chapters_dir_exists() {
        Ok(dir) => dir,
        Err(err) => return error(&err),
    };
    
    // 构建章节文件路径
    let file_path = chapters_dir.join(format!("{}.json", chapter.id));
    
    // 将章节序列化为JSON
    let json = match serde_json::to_string_pretty(&chapter) {
        Ok(json) => json,
        Err(e) => return error(&format!("无法序列化章节数据: {}", e)),
    };
    
    // 写入章节文件
    match fs::write(file_path, json) {
        Ok(_) => success(()),
        Err(e) => error(&format!("无法写入章节文件: {}", e)),
    }
}

// 调用AI接口命令
#[tauri::command]
async fn call_ai(request: AiRequest) -> ApiResponse<String> {
    // 验证请求
    if request.prompt.is_empty() {
        return error("提示不能为空");
    }
    
    // 获取OpenAI API密钥
    let api_key = match env::var("OPENAI_API_KEY") {
        Ok(key) => key,
        Err(_) => return error("未设置OpenAI API密钥，请在环境变量中配置OPENAI_API_KEY"),
    };
    
    // 估算token数量
    let prompt_tokens = estimate_tokens(&request.prompt);
    let context_tokens = request.context.as_ref().map_or(0, |ctx| estimate_tokens(ctx));
    let total_tokens = prompt_tokens + context_tokens;
    
    // 检查token数量是否超限(设置4000token的上限)
    if total_tokens > 4000 {
        return error("提示和上下文内容过长，请减少文本或分割请求");
    }
    
    // 构建系统提示
    let system_prompt = if request.context.is_some() {
        "你是一位写作助手。我会给你一些参考资料，请在回答问题时充分利用这些资料提供有帮助的建议。如果参考资料中包含当前正在编写的章节，重点关注这部分内容。保持回答简洁、友好且富有创意。"
    } else {
        "你是一位写作助手。请提供简洁、友好且富有创意的写作建议。"
    };
    
    // 构建用户提示
    let user_prompt = match &request.context {
        Some(context) => format!("参考资料：\n{}\n\n我的问题：{}", context, request.prompt),
        None => request.prompt.clone(),
    };
    
    // 构建OpenAI API请求
    let openai_request = OpenAiRequest {
        model: "gpt-3.5-turbo".to_string(),
        messages: vec![
            Message {
                role: "system".to_string(),
                content: system_prompt.to_string(),
            },
            Message {
                role: "user".to_string(),
                content: user_prompt,
            },
        ],
        temperature: 0.7,
    };
    
    // 创建HTTP客户端
    let client = reqwest::Client::builder()
        .timeout(Duration::from_secs(30)) // 30秒超时
        .build()
        .map_err(|e| format!("无法创建HTTP客户端: {}", e))?;
    
    // 发送请求到OpenAI API
    let response = client
        .post("https://api.openai.com/v1/chat/completions")
        .header("Content-Type", "application/json")
        .header("Authorization", format!("Bearer {}", api_key))
        .json(&openai_request)
        .send()
        .await;
    
    // 处理响应
    match response {
        Ok(res) => {
            if res.status().is_success() {
                match res.json::<OpenAiResponse>().await {
                    Ok(data) => {
                        if let Some(choice) = data.choices.get(0) {
                            success(choice.message.content.clone())
                        } else {
                            error("AI未返回有效响应")
                        }
                    }
                    Err(e) => error(&format!("无法解析API响应: {}", e)),
                }
            } else {
                // 处理API错误
                let status = res.status();
                if status.as_u16() == 429 {
                    error("API请求过于频繁，请稍后重试")
                } else {
                    match res.text().await {
                        Ok(err_text) => error(&format!("API错误 ({}): {}", status, err_text)),
                        Err(_) => error(&format!("API错误 ({})", status)),
                    }
                }
            }
        }
        Err(e) => {
            if e.is_timeout() {
                error("API请求超时，请稍后重试")
            } else {
                error(&format!("API请求失败: {}", e))
            }
        }
    }
}

// 主函数
fn main() {
    // 构建Tauri应用
    tauri::Builder::default()
        .setup(|app| {
            // 确保章节目录存在
            if let Err(err) = ensure_chapters_dir_exists() {
                eprintln!("警告: {}", err);
            }
            
            Ok(())
        })
        // 注册命令
        .invoke_handler(tauri::generate_handler![
            list_chapters,
            read_chapter,
            save_chapter,
            call_ai,
        ])
        // 启动应用
        .run(tauri::generate_context!())
        .expect("Tauri应用启动失败");
}